 /*******************************************************************************
  * Copyright (c) 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/

 package org.eclipse.osgi.framework.internal.core;

 import java.io.IOException ;
 import java.security.*;
 import java.util.*;
 import org.eclipse.osgi.framework.adaptor.PermissionStorage;
 import org.osgi.framework.FrameworkEvent;
 import org.osgi.service.condpermadmin.*;
 import org.osgi.service.permissionadmin.PermissionInfo;

 /**
  *
  * Implements ConditionalPermissionAdmin.
  */
 public class ConditionalPermissionAdminImpl implements ConditionalPermissionAdmin {
     public static final ConditionalPermissionInfoImpl[] EMPTY_COND_PERM_INFO = new ConditionalPermissionInfoImpl[0];
     public static final Condition[] EMPTY_COND = new Condition[0];
     public static final ConditionInfo[] EMPTY_COND_INFO = new ConditionInfo[0];
     public static final PermissionInfo[] EMPTY_PERM_INFO = new PermissionInfo[0];

     /**
      * The Vector of current ConditionalPermissionInfos.
      */
     private Vector condPerms;
     private Framework framework;
     private PermissionStorage storage;
     private long nextID = System.currentTimeMillis();

     /**
      * @param framework
      * @param permissionStorage
      */
     public ConditionalPermissionAdminImpl(Framework framework, PermissionStorage permissionStorage) {
         ConditionalPermissionInfoImpl.setConditionalPermissionAdminImpl(this);
         this.framework = framework;
         this.storage = permissionStorage;
         try {
             String [] encodedCondPerms = permissionStorage.getConditionalPermissionInfos();
             if (encodedCondPerms != null && encodedCondPerms.length > 0) {
                 condPerms = new Vector(encodedCondPerms.length);
                 for (int i = 0; i < encodedCondPerms.length; i++)
                     condPerms.add(new ConditionalPermissionInfoImpl(encodedCondPerms[i]));
             }
             else
                 condPerms = new Vector(0);
         } catch (IOException e) {
             framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e);
             condPerms = new Vector();
         }
     }

     /**
      * @see org.osgi.service.condpermadmin.ConditionalPermissionAdmin#addConditionalPermissionInfo(org.osgi.service.condpermadmin.ConditionInfo[], org.osgi.service.permissionadmin.PermissionInfo[])
      */
     public ConditionalPermissionInfo addConditionalPermissionInfo(ConditionInfo[] conds, PermissionInfo[] perms) {
         return setConditionalPermissionInfo(null, conds, perms);
     }

     public ConditionalPermissionInfo setConditionalPermissionInfo(String name, ConditionInfo conds[], PermissionInfo perms[]) {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null)
             sm.checkPermission(new AllPermission());
         if (name == null)
             name = "generated_" + Long.toString(nextID++); //$NON-NLS-1$
 ConditionalPermissionInfoImpl condPermInfo = null;
         synchronized (condPerms) {
             condPermInfo = (ConditionalPermissionInfoImpl) getConditionalPermissionInfo(name);
             if (condPermInfo == null) {
                 condPermInfo = new ConditionalPermissionInfoImpl(name, conds, perms);
                 condPerms.add(condPermInfo);
             } else {
                 condPermInfo.conds = conds;
                 condPermInfo.perms = perms;
             }
             saveCondPermInfos();
         }
         AbstractBundle bundles[] = framework.getAllBundles();
         for (int i = 0; i < bundles.length; i++) {
             AbstractBundle bundle = bundles[i];
             if (bundle.domain == null) {
                 continue;
             }
             BundleCombinedPermissions bcp = (BundleCombinedPermissions) bundle.domain.getPermissions();
             /* TODO I don't think we need this check */
             if (perms == null) {
                 continue;
             }

             bcp.checkConditionalPermissionInfo(condPermInfo);
         }
         return condPermInfo;
     }

     public ConditionalPermissionInfo getConditionalPermissionInfo(String name) {
         for (Enumeration eCondPerms = condPerms.elements(); eCondPerms.hasMoreElements();) {
             ConditionalPermissionInfoImpl condPerm = (ConditionalPermissionInfoImpl) eCondPerms.nextElement();
             if (name.equals(condPerm.getName()))
                 return condPerm;
         }
         return null;
     }

     /**
      * Returns an Enumeration of current ConditionalPermissionInfos. Each element will be of type
      * ConditionalPermissionInfoImpl.
      * @return an Enumeration of current ConditionalPermissionInfos.
      * @see org.osgi.service.condpermadmin.ConditionalPermissionAdmin#getConditionalPermissionInfos()
      */
     public Enumeration getConditionalPermissionInfos() {
         synchronized (condPerms) {
             return condPerms.elements();
         }
     }

     void deleteConditionalPermissionInfo(ConditionalPermissionInfo cpi) {
         synchronized (condPerms) {
             condPerms.remove(cpi);
             saveCondPermInfos();
         }
     }

     private void saveCondPermInfos() {
         try {
             String [] encodedCondPerms = new String [condPerms.size()];
             int i = 0;
             for (Enumeration eCondPerms = condPerms.elements(); eCondPerms.hasMoreElements(); i++)
                 encodedCondPerms[i] = eCondPerms.nextElement().toString();
             storage.saveConditionalPermissionInfos(encodedCondPerms);
         } catch (IOException e) {
             e.printStackTrace();
             framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e);
         }
     }

     /**
      * @see org.osgi.service.condpermadmin.ConditionalPermissionAdmin#getAccessControlContext(java.lang.String[])
      */
     public AccessControlContext getAccessControlContext(String [] signers) {
         Enumeration infos = getConditionalPermissionInfos();
         ArrayList permissionInfos = new ArrayList();
         if (infos != null) {
             while (infos.hasMoreElements()) {
                 ConditionalPermissionInfoImpl condPermInfo = (ConditionalPermissionInfoImpl) infos.nextElement();
                 ConditionInfo[] condInfo = condPermInfo.getConditionInfos();
                 boolean match = true;
                 for (int i = 0; i < condInfo.length; i++) {
                     if (BundleSignerCondition.class.getName().equals(condInfo[i].getType())) {
                         String [] args = condInfo[i].getArgs();
                         for (int j = 0; j < args.length; j++)
                             if (!framework.adaptor.matchDNChain(args[j], signers)) {
                                 match = false;
                                 break;
                             }
                     } else {
                         match = false;
                         break;
                     }
                 }
                 if (match) {
                     PermissionInfo[] addPermInfos = condPermInfo.getPermissionInfos();
                     for (int i = 0; i < addPermInfos.length; i++)
                         permissionInfos.add(addPermInfos[i]);
                 }
             }
         }
         BundlePermissionCollection collection = framework.permissionAdmin.createPermissions((PermissionInfo[]) permissionInfos.toArray(new PermissionInfo[permissionInfos.size()]), null, false);
         return new AccessControlContext(collection == null ? new ProtectionDomain[0] : new ProtectionDomain[] {new ProtectionDomain(null, collection)});
     }
 }

